/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package univalle.eisc.pais.ai.searcheslab.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import univalle.eisc.pais.ai.searcheslab.logic.Seeker;

/**
 *
 * @author victor
 */
public class Node implements Comparable<Node> {

    public int x;
    public int y;
    public int cost;
    public Node parent;
    public char operator;
    public int deepness;
    private List<Node> offsprings;

    public Node(Node parent, int x, int y, char operator) {
        this.parent = parent;
        this.x = x;
        this.y = y;
        this.operator = operator;
        this.cost = G();
        this.deepness = parent.deepness + 1;
    }

    public Node(int x, int y) {
        this.parent = null;
        this.x = x;
        this.y = y;
        this.operator = 'x';
        this.cost = 0;
        this.deepness = 1;
    }

    public int getCost() {
        return cost;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }

    public void addToCost(int newCost) {
        cost += newCost;
    }

    public int getElement() {
        return Stage.struct[y][x];
    }

    public void addOffspring(Node son) {
        offsprings.add(son);
    }

    public List<Node> getOffsprings() {
        if (offsprings == null) {
            offsprings = new ArrayList<Node>();
            offsprings.add(getUp());
            offsprings.add(getRight());
            offsprings.add(getDown());
            offsprings.add(getLeft());
            offsprings.removeAll(Collections.singleton(null)); //remove null nodes
            Seeker.expandedNodes += offsprings.size();
        }
        
        return offsprings;
    }

    public boolean isLeaf() {
        return offsprings == null || offsprings.isEmpty();

    }

    public Node getUp() {
        if (this.y != 0) {
            Node child = new Node(this, this.x, this.y - 1, 'u');
            if (!child.equals(this.parent)) {
                return child;
            }
        }
        return null;
    }

    public Node getDown() {
        if (this.y < Seeker.stage.getConfig().getN() - 1) {
            Node child = new Node(this, this.x, this.y + 1, 'd');
            if (!child.equals(this.parent)) {
                return child;
            }
        }
        return null;
    }

    public Node getLeft() {
        if (this.x != 0) {
            Node child = new Node(this, this.x - 1, this.y, 'l');
            if (!child.equals(this.parent)) {
                return child;
            }
        }
        return null;
    }

    public Node getRight() {
        if (this.x < Seeker.stage.getConfig().getN() - 1) {
            Node child = new Node(this, this.x + 1, this.y, 'r');
            if (!child.equals(this.parent)) {
                return child;
            }
        }
        return null;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 37 * hash + this.x;
        hash = 37 * hash + this.y;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        final Node other = (Node) obj;
        if (this.x != other.x || this.y != other.y) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Node {" + "x=" + x + ", y=" + y + '}';
    }

    @Override
    public int compareTo(Node o) {
        int v1 = this.getCost();
        int v2 = o.getCost();
        return (v1 < v2 ? -1 : (v1 == v2 ? 0 : 1));
    }

    private int G() {
        int g = parent.cost + 1 + Seeker.loadedWeight;
        if (Stage.struct[y][x] > 0) {
            g += Stage.struct[y][x];
        }
        return g;
    }

    public boolean isGoal() {
        return (Seeker.item1Right && Seeker.item2Right);
    }
}
